// QPART change here

/* -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
 * Copyright (c) 1997 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the Computer Systems
 *	Engineering Group at Lawrence Berkeley Laboratory.
 * 4. Neither the name of the University nor of the Laboratory may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
/* Ported from CMU/Monarch's code, nov'98 -Padma.*/

/* -*- c++ -*-
   priqueue.cc
   
   A simple priority queue with a remove packet function
   $Id: priqueue.cc,v 1.7 2004/10/07 17:56:03 haldar Exp $
   */

#include <object.h>
#include <queue.h>
#include <drop-tail.h>
#include <packet.h>
#include <cmu-trace.h>

// 1. QPART
#include "../aodv/aodv.h"
#include "../aodv/aodv_packet.h"


#include "priqueue.h"
#include <random.h>

#define time_interval 0.1


#define delta 0.002		//2 milli seconde
#define Pmax 250		//Pmax
//pile *MaListe = new pile;
//MaListe = malloc(sizeof(MaListe));
//MaListe = NIL;

int tableau [10];
double time = 0;
// end 1

typedef int (*PacketFilter)(Packet *, void *);

PriQueue_List PriQueue::prhead = { 0 };

// 2. QPART
Prio *prior = (Prio *)malloc(sizeof(Prio));
int i = 1;
// end 2

static class PriQueueClass : public TclClass {
public:
  PriQueueClass() : TclClass("Queue/DropTail/PriQueue") {}
  TclObject* create(int, const char*const*) {
    return (new PriQueue);
  }
} class_PriQueue;


PriQueue::PriQueue() : DropTail()
{
        bind("Prefer_Routing_Protocols", &Prefer_Routing_Protocols);
	LIST_INSERT_HEAD(&prhead, this, link);
}

int
PriQueue::command(int argc, const char*const* argv)
{
  if (argc == 2 && strcasecmp(argv[1], "reset") == 0)
    {
      Terminate();
      //FALL-THROUGH to give parents a chance to reset
    }
  return DropTail::command(argc, argv);
}

// 3. QPART
bool lookupprio(Prio *p, int fid)
{
Prio *pcour = (Prio *)malloc(sizeof(Prio));
pcour = p;

	if(pcour==NULL)
		return false;

	while(pcour)
	{
		if (pcour->fid == fid)
		{
                return true;
		}
	pcour=pcour->next;
	}
	return false;
}



Prio findprio(Prio *p, int fid)
{
Prio *pcour = (Prio *)malloc(sizeof(Prio));
//if(!pcour) return;	//Si l'allocation a �chou�e
*pcour = *p;
	while(pcour != NULL)
	{
		if (pcour->fid == fid)
		{
		return (*pcour);
		}
	pcour=pcour->next;			//EN PRINCIPE AVEC*
	}
	//return false;
    //      }
}


void insertprio(Prio **p, int fid, int prio, ns_addr_t src, ns_addr_t dst)	//ns_addr_t src, ns_addr_t dst
{
		Prio *pcour = (Prio *)malloc(sizeof(Prio));
		   //if(!pcour) return;	//Si l'allocation a �chou�e
		   pcour = *p;
		if (lookupprio(*p, fid)){ 	//si le fid  existe  deja alorscalcul_seuil
		while (pcour->fid != fid)
			{
			pcour = pcour->next;
			}
		pcour->prio = prio;
		pcour->src = src;
		pcour->dst = dst;
		} else 			//si le fid existe il suffit de mettre a jour sa periorit�
		   {
			//printf("fid n existe pas!!! je le cree\n");
			while (pcour->next != NULL)
				{
				pcour = pcour->next;
				}
			Prio *e = (Prio *)malloc(sizeof(Prio));
			//if(!e) return;	//Si l'allocation a �chou�e
			e->fid=fid;
			e->prio=prio;
			e->src=src;
			e->dst=dst;
			e->next=NULL;
			pcour->next = e;
		   }
}


void afficheprio(Prio *p)
{
Prio *pcour = (Prio *)malloc(sizeof(Prio));
*pcour = *p;
	while(pcour)
	{
		printf("FILE      fid  == %d  prio == %d\n",pcour->fid,pcour->prio);
		pcour=pcour->next;
		//printf("");
		//p=p->next;
		printf("********\n");
	}
	printf("*****************************\n\n");
}
// end 3

void
PriQueue::recv(Packet *p, Handler *h)
{
    struct hdr_cmn *ch = HDR_CMN(p);
    
    // 4. QPART
    beLength=0;
	qosLength=0;
	bool test=true;
	struct hdr_ip *ih = HDR_IP(p);

	//if(Prefer_Routing_Protocols) {
	if ( (ih->fid_ <= 10) && (ih->fid_ > 0)) {
		beLength = q_->len_;
		ih->qn_ = beLength;
		Queue::recv(p, h);
	}

	else //if (ih->fid_ > 10)		//QOS
	{

		qosLength = q_->len_;
		ih->qn_ = qosLength;

		recvHighPriority(p, h);
		//uptarget_->recv(p,h);
	}
    /*if(Prefer_Routing_Protocols) {

            switch(ch->ptype()) {
	case PT_DSR:
	case PT_MESSAGE:
            case PT_TORA:
            case PT_AODV:
                    recvHighPriority(p, h);
                    break;

            default:
                    Queue::recv(p, h);
            }
    }
    else {
            Queue::recv(p, h);
    }*/
	// end 4
}


void 
PriQueue::recvHighPriority(Packet *p, Handler *)
  // insert packet at front of queue
{
	// 5. QPART
	bool test=false;
	struct hdr_ip *ih = HDR_IP(p);
	// end 5
	q_->enqueHead(p);
	// 6. QPART
	insertprio(&prior,ih->fid_,ih->prio_, ih->src(), ih->dst());	//, ih->src_, ih->dst_
	// end 6
	if (q_->length() >= qlim_)
    {
      Packet *to_drop = q_->lookup(q_->length()-1);
      q_->remove(to_drop);
      drop(to_drop);
    }
  
  if (!blocked_) {
    /*
     * We're not blocked.  Get a packet and send it on.
     * We perform an extra check because the queue
     * might drop the packet even if it was
     * previously empty!  (e.g., RED can do this.)
     */
    p = deque();
    if (p != 0) {
      blocked_ = 1;
      target_->recv(p, &qh_);
    }
  } 
}
 
void 
PriQueue::filter(PacketFilter filter, void * data)
  // apply filter to each packet in queue, 
  // - if filter returns 0 leave packet in queue
  // - if filter returns 1 remove packet from queue
{
  int i = 0;
  while (i < q_->length())
    {
      Packet *p = q_->lookup(i);
      if (filter(p,data))
	{
	  q_->remove(p); // decrements q len
	}
      else i++;
    }
}

Packet*
PriQueue::filter(nsaddr_t id)
{
	Packet *p = 0;
	Packet *pp = 0;
	struct hdr_cmn *ch;

	for(p = q_->head(); p; p = p->next_) {
		ch = HDR_CMN(p);
		if(ch->next_hop() == id)
			break;
		pp = p;
	}

	/*
	 * Deque Packet
	 */
	if(p) {
		if(pp == 0)
			q_->remove(p);
		else
			q_->remove(p, pp);
	}
	return p;
}

/*
 * Called at the end of the simulation to purge the IFQ.
 */
void
PriQueue::Terminate()
{
	Packet *p;
	while((p = deque())) {
		drop(p, DROP_END_OF_SIMULATION);
		//drop(p);
		
	}
}




